#include "WmarkDev.h"

namespace android::wmark
{

    WmarkDev *WmarkDev::instance = NULL;
    int WmarkDev::ioctlDev(unsigned long cmd, void *msg)
    {
        if (!msg)
        {
            ALOGE("%s %d msg==NULL fail!!!\n", __func__, __LINE__);
            return -1;
        }

        mMutex.lock();
        int ret = ioctl(getFd(), cmd, msg);
        if (ret)
        {
            ALOGE("%s %d fail!!!\n", __func__, __LINE__);
        }
        mMutex.unlock();
        return ret;
    }

    int WmarkDev::initBufsNum(int num, unsigned long bufLen, int *fds)
    {
        int ret = -1;
        if (!fds || num > BUF_FD_MAX)
        {
            ALOGE("%s %d fds == NULL || num > %d\n", __func__, __LINE__, BUF_FD_MAX);
            return -1;
        }

        init_dma_bufs_t msg;
        msg.dma_buf_num = num;

        for (int i = 0; i < num; i++)
        {
            msg.dma_fds[i].buf_len = bufLen;
            msg.dma_fds[i].fd = fds[i];
            msg.dma_fds[i].index = i;
        }

        //  SET_INIT_DMA_BUFS
        ret = ioctlDev(SET_INIT_DMA_BUFS, (void *)&msg);
        if (ret)
        {
            ALOGE("%s %d: error", __func__, __LINE__);
        }

        return ret;
    }

    int WmarkDev::initWmarkBuf(int num, int w, int h, int ch)
    {
        int ret = -1;
        init_wmark_bufs_t msg = {0};

        msg.num = num;
        msg.len = w * h * ch;
        ALOGD("%s %d w . h . ch . num : %d.%d.%d.%d", __func__, __LINE__, w, h, ch, num);
        ret = ioctlDev(SET_INIT_WMARK_BUFS, (void *)&msg);
        if (ret)
        {
            ALOGE("%s %d: ret=%d error", __func__, __LINE__, ret);
        }
        return ret;
    }

    int WmarkDev::getFreeDmaBufIndex()
    {
        int ret = -1;
        uint32_t index = -1;
        wmark_buf_t msg;

        ret = ioctlDev(GET_FREE_BUF_INDEX_EXPORT, &msg);
        if (ret)
        {
            ALOGW("%s %d no get free dma_buf index", __func__, __LINE__);
            return ret;
        }

        index = msg.index;
        ALOGI("get free dma_buf index=%d", index);

        return index;
    }

    int WmarkDev::setUseDmaBufIndex(wmark_buf_t &msg)
    {
        int ret = -1;

        ret = ioctlDev(SET_USE_BUF_INDEX_EXPORT, &msg);
        if (ret)
        {
            ALOGE("%s %d : error", __func__, __LINE__);
            return ret;
        }
        return 0;
    }

    int WmarkDev::notifyStateChange(state_type_enum state)
    {
        int ret = -1;
        control_msg_t msg;

        msg.state = state;
        ret = ioctlDev(SET_MSG_CTL, &msg);

        return ret;
    }
    bool WmarkDev::threadLoop()
    {
        handlePoll();
        return true;
    }

    void WmarkDev::start()
    {
        this->run("server-wmarkdev-thread", android::PRIORITY_HIGHEST);
    }

    void WmarkDev::stop()
    {
        requestExitAndWait();
    }

    int WmarkDev::handlePoll()
    {
        struct epoll_event ev, events[MAX_EVENTS];
        int listen_sock, conn_sock, nfds, epollfd;
        uint32_t flag = EPOLLMSG;
        int wmark_dev_fd = getFd();
        int n = 0;

        epollfd = epoll_create1(0);
        if (epollfd == -1)
        {
            perror("epoll_create1");
            ALOGE("%s %d error: epoll_create1 %s", __func__, __LINE__, strerror(errno));
            return -1;
        }

        ev.events = flag;
        ev.data.fd = wmark_dev_fd;
        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, wmark_dev_fd, &ev) == -1)
        {
            perror("epoll_ctl:");
            ALOGE("%s %d error: epoll_ctl %s", __func__, __LINE__, strerror(errno));
            return -1;
        }

        for (;;)
        {
            nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
            if (nfds == -1)
            {
                perror("epoll_wait");
                ALOGE("%s %d error: epoll_wait %s", __func__, __LINE__, strerror(errno));
                return -1;
            }

            for (n = 0; n < nfds; ++n)
            {
                if (events[n].data.fd == wmark_dev_fd)
                {
                    if (events[n].events & EPOLLOUT)
                    {
                        ALOGD("event -> EPOLLOUT");
                    }
                    else if (events[n].events & EPOLLMSG)
                    {
                        ALOGD("event -> EPOLLMSG");
                        getMsgCtl();
                    }
                }
                else
                {
                    ALOGE("%s %d error.\n", __func__, __LINE__);
                }
            }
        }
        return 0;
    }

    int WmarkDev::getMsgCtl()
    {
        int ret = -1;
        control_msg_t msg;

        ret = ioctlDev(GET_MSG_CTL, &msg);
        if (ret)
        {
            ALOGE("%s %d error", __func__, __LINE__);
            return ret;
        }

        ALOGD("%s %d : sm=%d ", __func__, __LINE__, msg.state);

        if (mCtlMsgCallBack)
        {
            mCtlMsgCallBack->onResult(msg);
        }

        return ret;
    }
}